package com.weishuang.monitor.leader.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.weishuang.monitor.leader.commons.entity.BaseEntity;
import com.weishuang.monitor.leader.commons.enums.SCODE;
import com.weishuang.monitor.leader.commons.exception.CustomException;
import com.weishuang.monitor.leader.commons.tree.TreeFunctionImpl;
import com.weishuang.monitor.leader.commons.tree.TreeUtils;
import com.weishuang.monitor.leader.commons.utils.OtherUtils;
import com.weishuang.monitor.leader.commons.utils.UserUtils;
import com.weishuang.monitor.leader.entity.SysMenu;
import com.weishuang.monitor.leader.entity.dto.MenuDTO;
import com.weishuang.monitor.leader.entity.vo.MenuVO;
import com.weishuang.monitor.leader.mapper.SysMenuMapper;
import com.weishuang.monitor.leader.service.ISysMenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.weishuang.monitor.leader.service.SysCacheService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 菜单信息 服务实现类
 * </p>
 *
 * @author weishuang
 * @since 2021-03-23
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {

    @Autowired
    private SysCacheService sysCacheService;

    /**
     * 获取树形结构数据(不获取功能)
     * @param menu 筛选信息
     * @return
     */
    @Override
    public List<MenuVO> getTreeMenuList(MenuDTO menu) {
        List<MenuVO> menuList = baseMapper.getMenuList(menu);
        if (menuList != null) {
            menuList.forEach(menuVO -> {
                menuVO.setTitle(menuVO.getMenuName());
            });
        }
        TreeFunctionImpl<MenuVO> menuVOTreeFunction = TreeUtils.builder(MenuVO.class)
                .setIdColumn(MenuVO::getId)
                .setParentColumn(MenuVO::getParentId)
                .setChildrenColumn(MenuVO::getChildren);
        if (StringUtils.isNotBlank(menu.getParentId())) {
            menuVOTreeFunction.setParentId(menu.getParentId());
        }
        List<MenuVO> menuVOS = menuVOTreeFunction
                .buildTree(menuList);
        return menuVOS;
    }

    /**
     * 获取菜单列表
     * @param menu 筛选信息
     * @return
     */
    @Override
    public List<MenuVO> getMenuList(MenuDTO menu) {
        if (StringUtils.isBlank(menu.getParentId())) {
            menu.setParentId(SCODE.DEFUALT_PARENT_CODE.getValue());
        }
        List<MenuVO> menuList = baseMapper.getMenuList(menu);
        return menuList;
    }

    /**
     * 获取用户的菜单列表:缓存
     * @return
     */
    @Override
    public List<MenuVO> getMenuListByUserId() {
        String userId = UserUtils.getUserId();
        List<MenuVO> userMenuListByUserCode;
        if (UserUtils.isAdmin()) {
            userMenuListByUserCode = baseMapper.getSysManagerMenus();
        }else{
            userMenuListByUserCode = sysCacheService.getUserMenuListByUserCode(userId);
        }
        List<MenuVO> menuVOS = TreeUtils.builder(MenuVO.class)
                .setIdColumn(MenuVO::getId)
                .setParentColumn(MenuVO::getParentId)
                .setChildrenColumn(MenuVO::getChildren)
                .buildTree(userMenuListByUserCode);
        return menuVOS;
    }

    /**
     * 根据用户Code查询用户菜单：非缓存
     * @param userCode
     * @return
     */
    @Override
    public List<MenuVO> getUserMenuListByUserId(String userCode) {
        return baseMapper.getUserMenuListByUserId(userCode);
    }

    /***
     * 新增菜单
     * @param menu 菜单信息
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int addMenu(SysMenu menu) {
        menu.setId(IdWorker.getIdStr());
        if(menu.getTreeSort() == null){
            menu.setTreeSort(BigDecimal.valueOf(0));
        }
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getId,menu.getParentId());
        queryWrapper.eq(BaseEntity::getStatus, SCODE.STATUS_NORMAL.getValue());
        SysMenu parentMenu = baseMapper.selectOne(queryWrapper);
        if(parentMenu != null){
            //父存在
            //设置所有父级编号(父级的父级codes+父级code)
            menu.setParentIds(parentMenu.getParentIds()+","+parentMenu.getId());
            //设置所有级别排序号
            menu.setTreeSorts(parentMenu.getTreeSorts()+","+ OtherUtils.supplementTrees(menu.getTreeSort().toString()+""));
            //是否最末级，新增时如果当级为权限，不修改父级状态，如果不是权限最末级则修改父级不为最末级
            if (!SCODE.MENU_TYPE_PRO.getValue().equals(menu.getMenuType())) {
                LambdaUpdateWrapper<SysMenu> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(SysMenu::getTreeLeaf, SCODE.NO_CODE.getValue());
                updateWrapper.eq(SysMenu::getId, parentMenu.getId());
                this.update(updateWrapper);
            }
            //层次级别，默认为1，否则为父级加一
            menu.setTreeLevel(parentMenu.getTreeLevel().add(BigDecimal.valueOf(1)));
            //全节点名称没有父级为当前节点名称，有则父+当前
            menu.setTreeNames(parentMenu.getTreeNames()+","+menu.getMenuName());
        }else{
            //父不存在
            menu.setParentId(SCODE.DEFUALT_PARENT_CODE.getValue());
            menu.setParentIds(SCODE.DEFUALT_PARENT_CODE.getValue());
            //默认所有级别排序号
            menu.setTreeSorts(OtherUtils.supplementTrees(menu.getTreeSort()+""));
            //层次级别，默认为1，否则为父级加一
            menu.setTreeLevel(BigDecimal.valueOf(1));
            //全节点名称没有父级为当前节点名称，有则父+当前
            menu.setTreeNames(menu.getMenuName());
        }
        //是否最末级，新增的肯定是最末级，如果父级是最末级则修改父级不为最末级
        menu.setTreeLeaf(SCODE.YES_CODE.getValue());
        menu.insertInit();
        int insert = baseMapper.insert(menu);
        sysCacheService.clearSysMenuPermission();
        return insert;
    }

    /**
     * 修改菜单
     * @param menu 菜单信息
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateMenu(SysMenu menu) {
        SysMenu menu1 = baseMapper.selectById(menu.getId());
        if(menu1 == null){
            throw new CustomException("未找到菜单，请重试！");
        }
        if(!menu1.getMenuName().equals(menu.getMenuName())){
            //菜单名称改变了
            String join;
            if(StringUtils.isNotBlank(menu1.getTreeNames())){
                //如果有treeNames
                String[] names = menu1.getTreeNames().split(",");
                names[names.length-1] = menu.getMenuName();
                join = String.join(",", names);
                menu.setTreeNames(join);
            }else{
                //如果没有treeNames
                menu.setTreeNames(menu.getMenuName());
                join = menu.getMenuName();
            }
            //且不是最末级,则改变所有子的全节点名称
            if(SCODE.NO_CODE.getValue().equals(menu1.getTreeLeaf())){
                String treeNames = menu1.getTreeNames();
                int length = treeNames.length();
                //从多少开始替换
                baseMapper.replaceSonTreeName(menu.getId(),length+1,join);
            }
        }

        if(menu1.getTreeSort().compareTo(menu.getTreeSort()) != 0){
            //序号没改变
            //如果排序号有变
            if(menu1.getTreeSort().compareTo(menu.getTreeSort()) != 0){
                String join;
                if(StringUtils.isNotBlank(menu1.getTreeSorts())){
                    String[] split = menu1.getTreeSorts().split(",");
                    split[split.length - 1] = OtherUtils.supplementTrees(menu.getTreeSort()+"");
                    join = String.join(",",split);
                    menu.setTreeSorts(join);
                }else{
                    menu.setTreeSorts(menu.getTreeSort().toString());
                    join = OtherUtils.supplementTrees(menu.getTreeSort()+"");
                }
                //且不是最末级，则改变所有子的排序号。
                if(SCODE.NO_CODE.getValue().equals(menu1.getTreeLeaf())){
                    String treeSorts = menu1.getTreeSorts();
                    int length = treeSorts.length();
                    baseMapper.replaceSonTreeSorts(menu.getId(), length+1, join);
                }
            }
        }
        menu.updateInit();
        int i = baseMapper.updateMenu(menu);
        sysCacheService.clearSysMenuPermission();
        return i;
    }

    /**
     * 删除菜单并清除缓存
     * @param id
     * @return
     */
    @Override
    public int deleteMenu(String id) {
        SysMenu sysMenu = new SysMenu();
        sysMenu.setId(id);
        sysMenu.setStatus(SCODE.STATUS_DELETE.getValue());
        int i = baseMapper.updateById(sysMenu);
        sysCacheService.clearSysMenuPermission();
        return i;
    }

    /**
     * 获取用户权限
     * @param userId
     * @return
     */
    @Override
    public List<SysMenu> getSysMenuPermissionByUserId(String userId) {
        if (StringUtils.isBlank(userId)) {
            return new ArrayList<>();
        }
        List<SysMenu> menuPermissionList = baseMapper.getSysMenuPermissionByUserId(userId);
        return menuPermissionList;
    }

    /**
     * 查询当前用户所拥有的菜单：分配角色菜单
     * @param roleId 角色ID
     * @return
     */
    @Override
    public List<MenuVO> listMenuTreeByRoleId(String roleId) {
        //当前登录用户的用户信息。
        String userId = UserUtils.getUserId();
        boolean admin = UserUtils.isAdmin();
        //查询当前角色菜单，
        List<MenuVO> cUserMenu = baseMapper.getMenuListByUserId(userId,admin);
        if (cUserMenu != null) {
            cUserMenu.forEach(menuVO -> {
                menuVO.setTitle(menuVO.getMenuName());
            });
        }
        //查询被分配角色的菜单
        List<String> beUserMenuCodes = baseMapper.getUserHaveMenuCode(roleId);
        List<MenuVO> menuVOS = TreeUtils.builder(MenuVO.class)
                .setIdColumn(MenuVO::getId)
                .setParentColumn(MenuVO::getParentId)
                .setChildrenColumn(MenuVO::getChildren)
                .setCheckedIds(MenuVO::checked, beUserMenuCodes)
                .buildTree(cUserMenu);
        return menuVOS;
    }


}
